local base = _G
local math = base.math
module("gui")

SliderG = {}
SliderGMT = { __index = SliderG }

base.setmetatable(SliderG, { __index = ObjectG })

SliderG.create = function(x, y, width, height, segments, horizontal)
  local self = Object(x, y, width, height, SliderGMT)

  self.colors = get_colors('background', 'item', 'font')

  self.segments = segments or 10
  self.segments = math.max(self.segments, 1)
  self.value = 1
  self.old_value = self.value
  self.horizontal = horizontal or false

  return self
end

SliderG.destroy = function(self)
  self.segments = nil
  self.value = nil
  self.old_value = nil
  self.horizontal = nil
  
  self.colors = nil
  ObjectG.destroy(self)
end

SliderG.set_value = function(self, v)
  v = math.max(v, 1)
  v = math.min(v, self.segments)
  if self.value ~= v then
    self.old_value = self.value
    self.value = v
    self:on_change(v)
  end
end

-- handle mouse input
SliderG.mouse_press = function(self, button, x, y)
  -- convert mouse position to segment
  local v
  if self.horizontal == true then
    v = x/self.width * self.segments
  else
    v = y/self.height * self.segments
  end
  v = math.ceil(v)
  self:set_value(v)
end

SliderG.mouse_release = function(self, button, x, y)
  
end

SliderG.dragging = function(self, button, x, y)
  self:mouse_press(button, x, y)
end

-- scroll using the mouse wheel
SliderG.wheel_move = function(self, z)
  z = -z/120
  z = math.ceil(z)
  self:set_value(self.value + z)
end

-- handle key commands
SliderG.key_command = function(self, key, ctrl, shift)
  local dir = 0
  if self.horizontal == true then
    if key == base.KEY_LEFT then
      dir = -1
    elseif key == base.KEY_RIGHT then
      dir = 1
    end
  else
    if key == base.KEY_UP then
      dir = -1
    elseif key == base.KEY_DOWN then
      dir = 1
    end
  end
  if key == base.KEY_PGUP or key == base.KEY_HOME then
    dir = -self.value + 1
  elseif key == base.KEY_PGDOWN or key == base.KEY_END then
    dir = self.segments - self.value
  end
  self:set_value(self.value + dir)
end

SliderG.redraw = function(self, dt)
  local c = self.node.canvas
  c:clear()

  local alpha = 0.5
  if self.down == true then
    alpha = 1
  elseif self.is_hovered == true then
    alpha = 0.75
  end
  
  -- draw background rectangle
  local l, t, r, b = 0, -self.height, self.width, 0
  if self.colors.background then
    c:rect(l, t, r, b)
    c:set_fill_style(self.colors.background, 1)
    c:fill()
  end

  -- knob
  local w, h = self:get_size()
  local s = self.segments
  if s > 1 then
    local knob
    if self.horizontal == true then
      knob = math.max(w/s, 12)
    else
      knob = math.max(h/s, 12)
    end
    local ratio = (self.value - 1)/(s - 1)
    local x, y = w/2, -h/2
    if self.horizontal == true then
      local v = math.max(w - knob, 0)*ratio
      x = v + knob/2
      l, r = x - knob/2, x + knob/2
    else
      local v = math.max(h - knob, 0)*ratio
      y = -v - knob/2
      t, b = y - knob/2, y + knob/2
    end
    c:rect(l, t, r, b)
    c:set_fill_style(self.colors.item, alpha)
    c:fill()

    for i = -1, 1, 1 do
      for j = -1, 1, 1 do
        c:move_to(x + i * 2, y + j * 2)
        c:square(1)
        c:set_fill_style(self.colors.font, alpha/2)
        c:fill()
      end
    end
  end
end

SliderG.update = function(self, dt)
  -- check if the user has manually changed the value
  if self.value ~= self.old_value or self.value < 1 or self.value > self.segments then
    self.value = math.max(1, self.value)
    self.value = math.min(self.segments, self.value)
    self.old_value = self.value
  end
  -- todo: don't redaw all the time
  self:redraw(dt)
end

SliderG.on_change = function(self, value)
  
end

Slider = SliderG.create